import whiteImg from '../images/white.png';
import blackImg from '../images/black.png';
import {Chess} from './Constants';

/**
 * 棋盘对象，操作图形 API 绘图
 */
class ChessBoard {
    /** Canvas 元素的上下文对象 CanvasRenderingContext2D，用于调用各种 api 绘图 */
    context : CanvasRenderingContext2D;

    /** 单元格长度 */
    size : number = 20;
    /** 单元格数量 */
    count : number = 14;
    /** 棋盘位置偏移量，因为要绘制坐标标签，所以这个值一般是固定的（不要小于20即可） */
    offset = 50;
    /** 黑色棋子图像 */
    blackImage : HTMLImageElement;
    /** 白色棋子图像 */
    whiteImage : HTMLImageElement;

    /**
     * @param size 棋盘格子大小
     * @param count 棋盘线条数量
     * @param canvas 目标 HTMLCanvasElement 对象，绘制棋盘
     */
    constructor(size:number, count:number, canvas:HTMLCanvasElement){
        this.size = size;
        this.count = count-1;
        this.context = canvas.getContext('2d')!;
        this.blackImage = new Image();
        this.blackImage.src = blackImg;
        this.whiteImage = new Image();
        this.whiteImage.src = whiteImg;
        this.drawPanel();
    }

    /**
     * 绘制棋盘
     */
    drawPanel(){
        this.context.strokeStyle = "#000";
        this.context.lineWidth=1;
        this.context.lineCap = "square";
        this.context.lineJoin = "miter";
        this.context.fillStyle = "#eee";
        this.context.fillRect(0, 0, 500, 500);
        this.context.font = "14px 微软雅黑";
        this.context.textAlign = "center";
        this.context.textBaseline  = "middle";
        this.context.beginPath();
        let position = 0;
        let maxPosition = this.count * this.size + this.offset + 1;
        for (let index = 0; index <= this.count; index++) {
            position = index * this.size + this.offset; // 棋盘坐标映射成像素坐标，由于棋盘是正方形，所以只计算一次即可
            // 竖线
            this.context.moveTo(position, this.offset);
            this.context.lineTo(position, maxPosition);
            // 竖线上方的 X 轴标签
            this.context.fillStyle = "blue";
            // this.count + 1 - index
            this.context.fillText(1 + index + "", position, this.offset - 25, 20);
            // 横线
            this.context.moveTo(this.offset, position);
            this.context.lineTo(maxPosition, position);
            // 横线左外侧的 Y 轴标签
            this.context.fillStyle = "green";
            // 65 + this.count - index
            this.context.fillText(String.fromCharCode(65 + index), this.offset - 25, position + 2, 10);
        }
        this.context.stroke();
        // 正中心的大圆点（围棋术语叫天元）
        position = Math.floor(this.count/2) * this.size + this.offset;
        this.context.moveTo(position, position);
        this.context.arc(position, position, 5, 0, 2*Math.PI);
        // 4个定位圆点，均匀分布于棋盘四方
        let left = Math.floor(this.count/4);
        let p1 = left * this.size + this.offset;
        let p2 = (this.count - left) * this.size + this.offset;
        this.context.fillStyle = "red";
        this.context.moveTo(p1, p1);
        this.context.arc(p1, p1, 5, 0, 2*Math.PI);
        this.context.moveTo(p2, p2);
        this.context.arc(p2, p2, 5, 0, 2*Math.PI);
        this.context.moveTo(p1, p2);
        this.context.arc(p1, p2, 5, 0, 2*Math.PI);
        this.context.moveTo(p2, p1);
        this.context.arc(p2, p1, 5, 0, 2*Math.PI);
        this.context.fill();
        this.context.closePath();
    }

    /**
     * 绘制棋子
     * @param x 棋子 x 坐标
     * @param y 棋子 y 坐标
     * @param type 棋子类型，黑子或者白子
     */
    drawChess(x:number, y:number, type:Chess){
        if(this.forbidText[type]){
            return;
        }
        let offset = 0;
        if(type===Chess.BLACK){
            offset = 2; // 黑棋需要添加偏移量，否则会画歪（原因是切图没切好）
        }
        this.context.drawImage(type===Chess.WHITE?this.whiteImage:this.blackImage, 
            x* this.size + this.offset - this.size*0.5 - offset,
            y* this.size + this.offset - this.size*0.5 - offset, 
            this.size, 
            this.size);
    }

    private forbidText : {[key:string]:string} = { "empty-ban-white":"白", "empty-ban-black":"黑", "empty-ban-all":"全" };

    /**
     * 绘制禁手标记
     */
    drawForbid(x:number, y:number, type:Chess){
        if(this.forbidText[type]){
            this.context.beginPath();
            this.context.strokeStyle = "black";
            this.context.fillStyle = "gray";
            this.context.lineWidth=1;
            this.context.moveTo(x * this.size + this.offset, y * this.size + this.offset);
            this.context.arc(x * this.size + this.offset, y * this.size + this.offset, 12, 0, 2*Math.PI);
            this.context.fill();
            this.context.stroke();
            this.context.fillStyle = "white";
            this.context.fillText(this.forbidText[type], x * this.size + this.offset, y * this.size + this.offset, 20);
            this.context.closePath();
        }
    }

    /**
     * 绘制线段（一般用于标记连成 5 子的棋子）
     * @param sx 起始 x 坐标
     * @param sy 起始 y 坐标
     * @param ex 结束 x 坐标
     * @param ey 结束 y 坐标
     */
    drawLine(sx:number, sy:number, ex:number, ey:number){
        this.context.beginPath();
        this.context.lineWidth=5;
        this.context.strokeStyle = "red";
        this.context.moveTo(sx * this.size + this.offset, sy * this.size + this.offset);
        this.context.lineTo(ex * this.size + this.offset, ey * this.size + this.offset);
        this.context.stroke();
        this.context.closePath();
    }

    /**
     * 标记棋盘某一个位置
     * @param x 棋盘 x 坐标
     * @param y 棋盘 y 坐标
     */
    highLightChess(x:number, y:number){
        this.context.beginPath();
        this.context.fillStyle = "#f7eea2";
        const [px, py] = [ x * this.size + this.offset, y * this.size + this.offset ];
        this.context.moveTo(px, py);
        this.context.arc(px, py, 20, 0, 2*Math.PI);
        this.context.fill();
    }

    /**
     * 将屏幕坐标映射成棋盘棋子的坐标轴索引
     * @param position 像素坐标
     * @returns 坐标轴索引
     */
    getCoordinate(position:number){
        let coordinate = Math.floor((position - this.offset + this.size*0.5)/this.size);
        if(coordinate<0) coordinate = 0;
        if(coordinate>this.count) coordinate = this.count;
        return coordinate;
    }
}


export default ChessBoard;